home *** CD-ROM | disk | FTP | other *** search
- /*
- MOD 07-12-87 MAZ - RIFF compression code
- */
- #include <FileMgr.h>
- #include "MAZlib.h"
-
- #define assembly 1
-
- extern unsigned char *body[];
- extern short nrows;
- extern short ncols;
-
- /* forwards */
- bool unhuffscan();
- short huffscan();
-
- /* readin and decompress a picture */
- bool COMPinput(io, huffbuff, chunk)
- ioParam *io;
- short *huffbuff;
- short chunk;
- {
- register short i, j, k, flat;
- register unsigned char *p, *q, *start;
-
- /* determine size of a flat scan line */
- flat = (4 + ncols) & ~1;
- /* read the file scan by scan */
- for (i = 0, start = body[chunk]; i < nrows; i++, start += ncols)
- {
- /* get the scan line header */
- getbytes(io, huffbuff, 4L);
- if (huffbuff[1] > flat || huffbuff[1] < 6)
- {
- /* bad data read */
- bad_data:
- SysBeep(1);
- return(false);
- }
- /* get rest of this scan line */
- getbytes(io, huffbuff+2, (long)(huffbuff[1] - 4));
- /* uncompress the delta's */
- if (!unhuffscan(huffbuff, start, ncols))
- goto bad_data;
- }
- /* now undo the delta calculations in memory */
- /* undo vertical deltas */
- for (i = 1, p = body[chunk], q = p + ncols; i < nrows; i++)
- for (j = 0; j < ncols; j++)
- {
- k = *p;
- p++;
- *q += k;
- q++;
- }
- /* undo horizontal deltas */
- for (i = 0, p = body[chunk]; i < nrows; i++, p++)
- for (j = 0; j < ncols-1; j++)
- {
- k = *p;
- p++;
- *p += k;
- }
- /* success */
- return(true);
- }
-
- /* output in compressed format */
- /* this procedure coerces the buffer from 256 to "desired_nsamples" samples */
- COMPoutput(io, ptr, huffbuff, RLEbuf)
- ioParam *io;
- unsigned char *ptr;
- short *huffbuff;
- short *RLEbuf;
- {
- register short i, j, k, flat;
- long outbytes;
- unsigned char *base;
- register unsigned char *p, *q, *start;
-
- /* compute first order (horizontal) deltas */
- for (i = 0, start = ptr; i < nrows; i++, start += ncols)
- for (j = 0, p = start + ncols; j < ncols-1; j++)
- {
- p--;
- k = *(p-1);
- *p -= k;
- }
- /* compute second order (vertical delta of deltas) deltas */
- start = ptr + (long)ncols * (long)(nrows - 1);
- for (i = 1; i < nrows; i++, start -= ncols)
- for (j = 0, p = start, q = start - ncols; j < ncols; j++)
- {
- k = *q;
- q++;
- *p -= k;
- p++;
- }
- /* note that the first byte of the file is actual data (the anchor) */
- /* the first scanline otherwise consists of first order deltas */
- /* the rest of the scanlines begin with one byte of first order delta */
- /* and follow with second order deltas */
- /* determine size of a flat scan line */
- flat = (4 + ncols) & ~1;
- outbytes = 0;
- for (i = 0, p = ptr; i < nrows; i++, p += ncols)
- {
- j = huffscan(p, ncols, huffbuff);
- #if 0
- k = RLEscan(p, ncols, RLEbuf);
- #endif
- /* determine if it's smaller unpacked (deltas) */
- if (j > flat)
- {
- j = *p & 0x00FF;
- huffbuff[0] = (1<<8) + j; /* mark flat scan */
- huffbuff[1] = flat;
- /* prezero to pack end with a zero byte */
- huffbuff[flat/2 - 1] = 0;
- cpybuf(&huffbuff[2], p+1, ncols - 1);
- j = flat;
- }
- putbytes(io, huffbuff, (long)j);
- outbytes += j;
- }
- flushbytes(io);
- /* now undo the delta calculations in memory, to restore picture back to normal */
- /* first undo vertical deltas */
- for (i = 1, p = ptr, q = p + ncols; i < nrows; i++)
- for (j = 0; j < ncols; j++)
- {
- k = *p;
- p++;
- *q += k;
- q++;
- }
- /* second undo horizontal deltas */
- for (i = 0, p = ptr; i < nrows; i++, p++)
- for (j = 0; j < ncols-1; j++)
- {
- k = *p;
- p++;
- *p += k;
- }
- }
-
- /*
- uncompress a compressed scan line
- return true if scan is OK, false if it would not parse
- */
- bool unhuffscan(buffer, start, count)
- short *buffer;
- register unsigned char *start;
- short count;
- {
- short flag;
- register short ac, byte;
- register char bitsin;
- register short *q;
- register unsigned char *p;
- /* this macro gets the next bit from input - it is left in the sign bit of "ac" */
- #define getbit ac += ac; if (--bitsin == 0) { ac = *q++; bitsin = 16; }
-
- flag = buffer[0]>>8;
- if (flag == 1)
- {
- p = start;
- *p++ = buffer[0] & 0x00FF;
- cpybuf(p,&buffer[2],count-1);
- }
- else if (flag == 0)
- {
- p = start;
- start += count;
- *p++ = buffer[0];
- q = buffer+2;
- ac = *q++;
- bitsin = 16;
- while (p < start)
- {
- /*
- these nested "if" statements parse the huffman-code
- tree for RIFF compressed file encoding.
- at the leaves of the tree are statements like so:
-
- *p++ = nnn;
-
- these statements write a sample delta byte to the output buffer
- the parse tree nodes are commented with the bitstrings
- that they map onto. an ellipsis in the comment indicates
- an internal tree node.
- */
- if (ac >= 0)
- {
- /* 0 */
- *p++ = 0;
- getbit
- }
- else
- {
- /* 1... */
- getbit
- if (ac >= 0)
- {
- /* 10... */
- getbit
- if (ac >= 0)
- {
- /* 100 */
- *p++ = 1;
- getbit
- }
- else
- {
- /* 101 */
- *p++ = 255;
- getbit
- }
- }
- else
- {
- /* 11... */
- getbit
- if (ac >= 0)
- {
- /* 110... */
- getbit
- if (ac >= 0)
- {
- /* 1100 */
- *p++ = 2;
- getbit
- }
- else
- {
- /* 1101 */
- *p++ = 254;
- getbit
- }
- }
- else
- {
- /* 111... */
- getbit
- if (ac >= 0)
- {
- /* 1110... */
- getbit
- if (ac >= 0)
- {
- /* 11100 */
- *p++ = 3;
- getbit
- }
- else
- {
- /* 11101 */
- *p++ = 253;
- getbit
- }
- }
- else
- {
- /* 1111... */
- getbit
- if (ac >= 0)
- {
- /* 11110... */
- getbit
- if (ac >= 0)
- {
- /* 111100 */
- *p++ = 4;
- getbit
- }
- else
- {
- /* 111101 */
- *p++ = 252;
- getbit
- }
- }
- else
- {
- /* 11111... */
- getbit
- if (ac >= 0)
- {
- /* 111110... */
- getbit
- if (ac >= 0)
- {
- /* 1111100 */
- *p++ = 5;
- getbit
- }
- else
- {
- /* 1111101 */
- *p++ = 251;
- getbit
- }
- }
- else
- {
- /* 111111... */
- getbit
- if (ac >= 0)
- {
- /* 1111110... */
- getbit
- if (ac >= 0)
- {
- /* 11111100 */
- *p++ = 6;
- getbit
- }
- else
- {
- /* 11111101 */
- *p++ = 250;
- getbit
- }
- }
- else
- {
- /* 1111111... */
- getbit
- if (ac >= 0)
- {
- /* 11111110... */
- getbit
- if (ac >= 0)
- {
- /* 111111100 */
- *p++ = 7;
- getbit
- }
- else
- {
- /* 111111101 */
- *p++ = 249;
- getbit
- }
- }
- else
- {
- /* 11111111... */
- /* decode an eight-bit delta which follows */
- /* the escape code */
- byte = 0;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- byte += byte;
- getbit
- if (ac < 0)
- byte++;
- /* check for bad data */
- if (byte < 8 || byte > 248)
- return(false);
- *p++ = byte;
- getbit
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- else if (flag == 2)
- {
- /* input RLE scanline */
- }
- else
- return(false);
- /* success */
- return(true);
- }
-
- #if assembly
- /* output a compressed scanline definition */
- short huffscan(p, count, buffer)
- register unsigned char *p;
- register short count;
- short *buffer;
- {
- register short bitsin, byte, ac;
- register short *q, *disp;
-
- asm
- {
- MOVEA.L buffer,q
- MOVEQ #0,byte
- MOVE.B (p)+,byte
- SUBQ.W #1,count
- MOVE.W byte,(q)+ ; write out zero byte (marks compressed scan) and first byte
- MOVE.W #0,(q)+ ; reserve space for count word
- MOVEQ #0,ac
- MOVE.B ac,bitsin
- hufflp: TST.W count
- BGT.S @fetch
- TST.B bitsin ; write out last part
- BLE.S @nolast
- SUBI.B #16,bitsin
- NEG.B bitsin
- ASL.W bitsin,ac
- MOVE.W ac,(q)+
- nolast: goto endhuff
- fetch: MOVEQ #0,byte
- MOVE.B (p)+,byte
- SUBQ.W #1,count
- CMPI.W #7,byte
- BLE.S @disp1
- CMPI.W #249,byte
- BGE.S @disp2
- BRA @defaul
- disp1: LEA @table,disp ; load dispatch table addr
- ADD.W byte,byte ; get byte times two
- ADD.W @table(byte),byte ; get offset from table to code
- JMP @table(byte) ; dispatch
- table: DC.W @case0
- DC.W @case1
- DC.W @case2
- DC.W @case3
- DC.W @case4
- DC.W @case5
- DC.W @case6
- DC.W @case7
- disp2: LEA @tabl2,disp ; load dispatch table addr
- SUBI.W #249,byte
- ADD.W byte,byte ; get byte times two
- ADD.W @tabl2(byte),byte ; get offset from tabl2 to code
- JMP @tabl2(byte) ; dispatch
- tabl2: DC.W @cas249
- DC.W @cas250
- DC.W @cas251
- DC.W @cas252
- DC.W @cas253
- DC.W @cas254
- DC.W @cas255
- case7: BSR.S @onebit
- case6: BSR.S @onebit
- case5: BSR.S @onebit
- case4: BSR.S @onebit
- case3: BSR.S @onebit
- case2: BSR.S @onebit
- case1: BSR.S @onebit
- BSR.S @zerbit
- case0: BSR.S @zerbit
- BRA.S @hufflp
- cas249: BSR.S @onebit
- cas250: BSR.S @onebit
- cas251: BSR.S @onebit
- cas252: BSR.S @onebit
- cas253: BSR.S @onebit
- cas254: BSR.S @onebit
- cas255: BSR.S @onebit
- BSR.S @zerbit
- BSR.S @onebit
- BRA @hufflp
- ; shift a one into our collection register
- onebit: ADD.W ac,ac
- ADDQ.W #1,ac
- ADDQ.B #1,bitsin
- CMPI.B #16,bitsin
- BNE.S @oneret
- MOVE.W ac,(q)+
- MOVEQ #0,ac
- MOVE.B ac,bitsin
- oneret: RTS
- ; shift a zero into our collection register
- zerbit: ADD.W ac,ac
- ADDQ.B #1,bitsin
- CMPI.B #16,bitsin
- BNE.S @zerret
- MOVE.W ac,(q)+
- MOVEQ #0,ac
- MOVE.B ac,bitsin
- zerret: RTS
- ; shift in 8 bits of ones followed by the 8-bit (delta) code
- defaul: BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- BSR.S @onebit
- ; now shift in the 8-bit delta code itself.
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- ASL.B #1,byte
- ADDX.W ac,ac ; shift in a bit
- BSR.S @putbit
- BRA @hufflp
- ; a little subroutine to shift our bit collection register.
- putbit: ADDQ.B #1,bitsin
- CMPI.B #16,bitsin
- BNE.S @bitret
- MOVE.W ac,(q)+
- MOVEQ #0,ac
- MOVE.B ac,bitsin
- bitret: RTS
- }
- endhuff:
- /* write out count word */
- ac = (q - buffer) * 2;
- buffer[1] = ac;
- return(ac);
- }
- #else
- /* output a compressed scanline definition */
- short huffscan(p, count, buffer)
- register unsigned char *p;
- register short count;
- short *buffer;
- {
- register short bitsin, byte, ac;
- register short *q;
-
- q = buffer;
- /* put out first byte by itself at beginning (as a word) */
- *q++ = *p++;
- count--;
- q++; /* skip count word */
- /* set up bit output buffer - a short */
- ac = 0;
- bitsin = 0;
- while (count > 0)
- {
- /* fetch data byte */
- byte = *p;
- p++;
- count--;
- /* output it in bits */
- switch (byte)
- {
- case 7:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 6:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 5:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 4:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 3:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 2:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 1:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac; /* shift in a zero */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 0:
- ac += ac; /* shift in a zero */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- break;
- case 249:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 250:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 251:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 252:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 253:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 254:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- case 255:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac; /* shift in a zero */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- break;
- default:
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + 1; /* shift in a one */
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- /* now shift in the 8-bit code */
- ac += ac + ((byte>>7)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>6)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>5)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>4)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>3)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>2)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + ((byte>>1)&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- ac += ac + (byte&1);
- bitsin++;
- if (bitsin == 16)
- {
- *q++ = ac;
- bitsin = ac = 0;
- }
- break;
- }
- }
- /* now write out last part */
- if (bitsin > 0)
- *q++ = ac << (16 - bitsin);
- /* write out count word */
- ac = (q - buffer) * 2;
- buffer[1] = ac;
- return(ac);
- }
- #endif
-